
package edu.uoc.tdp.servidor.bbdd.proves;

import edu.uoc.tdp.beans.proves.RondaEliminatoria;
import edu.uoc.tdp.beans.proves.RondaFinal;
import edu.uoc.tdp.bbdd.GestorDiscConnexio;
import edu.uoc.tdp.beans.proves.PreguntaResposta;
import edu.uoc.tdp.beans.proves.Ronda;
import edu.uoc.tdp.common.EOlympicsException;
import edu.uoc.tdp.common.EOlympicsExceptionProva;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.List;

/**
 * Classe gestora de Rondes
 * @author Grup tdp 1x4J
 */

public class GestorRonda {
    private GestorDiscConnexio gestor;
    private Connection connexio;    
    
    /**
     * Constructor generic de GestorRonda
     */
    public GestorRonda(){
        this.gestor=new GestorDiscConnexio();
        this.connexio=gestor.getConnexio();         
    }
    /**
     * Constructor amb un paràmetre. 
     * @param pGestor           Gestor de disc genèric 
     */
    public GestorRonda(GestorDiscConnexio pGestor){
        this.gestor=pGestor;
        connexio=gestor.getConnexio();
    }
    /**
     * Accessor de lectura, obté una ronda eliminatòria.
     * @param idProva               Identificador d'una prova
     * @return  RondaEliminatoria   Una ronda eliminatoria
     * @throws SQLException
     * @throws EOlympicsException 
     */
    
    public RondaEliminatoria getRondaEliminatoria(Integer idProva) throws  EOlympicsException, SQLException{        
       RondaEliminatoria ronda=null;       
        Statement st=gestor.creaSentencia();
        String sql="SELECT R.nombrePreguntes,R.dataIniciRealitzacio,R.dataFiRealitzacio, "
                + "R.dataBaixa,R.dataMod "
                + "FROM RONDA R "                
                + "WHERE R.idProva="+ idProva 
                + " And R.tipusRonda='E'";  
            ResultSet rs=st.executeQuery(sql);
            if (rs.next()){                              
                ronda= new RondaEliminatoria(rs.getInt(1),rs.getDate(2),rs.getDate(3),
                                 getPreguntesRespostesRonda(idProva,"E"));
                ronda.setDataBaixa(rs.getDate(4));
                ronda.setDataModificacio(rs.getDate(5));
            }
            st.close();
            rs.close();
        return ronda;
    } 
    /**
     * Obté una ronda final d'una prova
     * @param idProva               identificador d'una prova
     * @return  Ronda final
     * @throws EOlympicsException
     * @throws SQLException 
     */
    public RondaFinal getRondaFinal(Integer idProva) throws  EOlympicsException, SQLException{
       RondaFinal ronda=null;       
        Statement st=gestor.creaSentencia();
        String sql="SELECT R.nombrePreguntes,R.dataIniciRealitzacio,R.dataFiRealitzacio, "
                + "R.dataBaixa,R.dataMod "
                + "FROM RONDA R "                
                + "WHERE R.idProva="+ idProva 
                + " And R.tipusRonda='F'";   
            ResultSet rs=st.executeQuery(sql);
            if (rs.next()){                              
                ronda= new RondaFinal(rs.getInt(1),rs.getDate(2),rs.getDate(3),
                                 getPreguntesRespostesRonda(idProva,"F"));
                ronda.setDataBaixa(rs.getDate(4));
                ronda.setDataModificacio(rs.getDate(5));                
            }
            st.close();
            rs.close();
          
        return ronda;
    }
    
    /**
     * Accessor de lectura que obté una ronda
     * @param idProva               identificador de la prova
     * @param tipus                 identificador de la ronda (E: eliminatoria, F: final)
     * @return ronda                Una ronda
     * @throws SQLException
     * @throws EOlympicsException 
     */
    private Ronda getRonda(Integer idProva, String tipus) throws  EOlympicsException, SQLException{
        Ronda ronda=null;       
        Statement st=gestor.creaSentencia();
        String sql="SELECT R.nombrePreguntes,R.dataIniciRealitzacio,R.dataFiRealitzacio,"
                + "dataAlta,dataBaixa,dataMod "
                + "FROM RONDA R "                
                + "WHERE R.idProva="+ idProva 
                + " And R.tipusRonda='"+tipus+"'";
        
            ResultSet rs=st.executeQuery(sql);
            if (rs.next()){                              
                ronda= new Ronda(rs.getInt(1),rs.getDate(2),rs.getDate(3),
                                 getPreguntesRespostesRonda(idProva,tipus));
                
                ronda.setDataAlta(rs.getDate(4));
                ronda.setDataBaixa(rs.getDate(5));
                ronda.setDataModificacio(rs.getDate(6));
            }
            st.close();
            rs.close();
                
        return ronda;
    }
    /**
     * Accessor de lectura que obté les preguntes i respostes d'una ronda
     * @param idProva               Identificador de la prova
     * @param tipus                 E: Ronda eliminatoria, F: Ronda final
     * @return pr                   Llista de Preguntes i respostes de la ronda
     * @throws EOlympicsExceptionRonda
     * @throws EOlympicsException 
     */
    private List<PreguntaResposta> getPreguntesRespostesRonda(Integer idProva, String tipus) throws EOlympicsExceptionProva, EOlympicsException, SQLException{
        List<PreguntaResposta>pr=new ArrayList <PreguntaResposta>();
        Statement st=gestor.creaSentencia();
        String sql="SELECT numPregunta,opcioCorrecta "
                + "FROM RESPOSTACORRECTA "
                + "WHERE idProva="+idProva+" "
                + "AND tipusRonda='"+tipus+"' "
                + "ORDER BY numPregunta";
       
            ResultSet rs=st.executeQuery(sql);
            while (rs.next()){
                pr.add(new PreguntaResposta(rs.getInt(1),rs.getString(2)));
            }
        
        return pr;
    }
    /**
     * Accessor d'escriptura, guarda una ronda eliminatòria a la BBDD.
     * @param idProva                   idenficador de prova.
     * @param ronda                     Ronda Eliminatoria
     * @return Cert: si realitza l'escriptura, Fals: en cas contrari.
     * @throws EOlympicsExceptionRonda
     * @throws EOlympicsException 
     */
    public boolean setAltaRondaEliminatoria(Integer idProva,RondaEliminatoria ronda) throws EOlympicsExceptionProva, EOlympicsException, SQLException{        
        return setAltaRonda(idProva,"E",ronda);
    }
   
    /**
     * Acessor d'escriptua, guarda una ronda Final a la BBDD
     * @param idProva               identificador de prova.
     * @param ronda                 Ronda Final
     * @return Cert: si realitza l'escriptura, Fals: en cas contrari.
     * @throws EOlympicsExceptionRonda
     * @throws EOlympicsException 
     */
    public boolean setAltaRondaFinal(Integer idProva,RondaFinal ronda) throws EOlympicsExceptionProva, EOlympicsException, SQLException{        
        return setAltaRonda(idProva,"F",ronda);
    }
    /**
     * Guarda les modificacions d'una ronda eliminatoria
     * @param idProva                   identificador d'una prova
     * @param ronda                     Ronda a guardar
     * @throws EOlympicsException
     * @throws EOlympicsExceptionProva
     * @throws SQLException 
     */        
    public void setModificacioRondaEliminatoria(Integer idProva,RondaEliminatoria ronda) throws EOlympicsException, EOlympicsExceptionProva, SQLException{
        setModificacioRonda(idProva,"E",ronda);        
        
    }
    /**
     * Guarda les modificacions d'una ronda final
     * @param idProva           identificador de la prova
     * @param ronda             Ronda a guardar
     * @throws EOlympicsException
     * @throws EOlympicsExceptionProva
     * @throws SQLException 
     */
    public void setModificacioRondaFinal(Integer idProva,RondaFinal ronda) throws EOlympicsException, EOlympicsExceptionProva, SQLException{
        setModificacioRonda(idProva,"F",ronda);        
    }
    
    
    /**
     * Accessor d'escriptura, guarda una ronda a la BBDD
     * @param idProva                   identificador de prova
     * @param tipus                     identificador de Ronda
     * @param ronda                     una Ronda
     * @return Cert: si realitza l'escriptura, Fals: en cas contrari.
     * @throws EOlympicsExceptionRonda
     * @throws EOlympicsException 
     */
    private boolean setAltaRonda(Integer idProva,String tipus,Ronda ronda) throws EOlympicsExceptionProva, EOlympicsException, SQLException{
        boolean confirmat=false;
        Statement st=gestor.creaSentencia();        
        String sql="INSERT INTO RONDA "
                + "(idProva,tipusRonda,nombrePreguntes,dataIniciRealitzacio,dataFiRealitzacio,"
                + "dataAlta,usuariAlta) "
                + "VALUES(?,?,?,?,?,?,?)";
//       try{
          
           PreparedStatement ps = gestor.crearPreparedStatement(sql);
           ps.setInt(1, idProva);
           ps.setString(2, tipus);
           ps.setInt(3, ronda.getNombrePreguntes());
           ps.setDate(4, new java.sql.Date(ronda.getDataIniRealitzacio().getTime())); 
           ps.setDate(5, new java.sql.Date(ronda.getDataFiRealitzacio().getTime())); 
           ps.setDate(6, new java.sql.Date(System.currentTimeMillis())); 
           ps.setInt(7, ronda.getUsuariAlta().getIdIntern());
           ps.execute();
           ps.close();                     
           setAltaRespostesRonda(idProva,tipus,ronda);           
           confirmat=true;

        return confirmat;
    }
    
    /**
     * Acessor d'escriptura, guarda les preguntes i respostes d'una ronda.
     * @param idProva                   Identificador de prova
     * @param tipus                     Identificador de ronda
     * @param preguntes                 Llista de preguntes i respostes
     * @return n                        Numero de transaccions realitzades.
     * @throws EOlympicsExceptionRonda
     * @throws EOlympicsException 
     */
    private int setAltaRespostesRonda(Integer idProva, String tipus,Ronda ronda) throws EOlympicsExceptionProva, EOlympicsException, SQLException{
        String sql="INSERT INTO RESPOSTACORRECTA "
                + " (idProva,tipusRonda,numPregunta,opcioCorrecta,"
                + "dataAlta,usuariAlta) "
                + "VALUES(?,?,?,?,?,?)";        
        Integer n=0;
//        try{
           PreparedStatement ps = gestor.crearPreparedStatement(sql);
           for(PreguntaResposta pr:ronda.getRespostesRonda()){
                ps.setInt(1, idProva);               
                ps.setString(2,tipus);                
                ps.setInt(3,pr.getPregunta());
                ps.setString(4, pr.getResposta());
                ps.setDate(5, new java.sql.Date(System.currentTimeMillis())); 
                ps.setInt(6, ronda.getUsuariAlta().getIdIntern());
                if(ps.execute()) n++;
           }            
           ps.close();
           
        
        return n;
    }   
    private int setModificacioRespostesRonda(Integer idProva, String tipus,Ronda ronda) throws EOlympicsExceptionProva, EOlympicsException, SQLException{

        String sql="INSERT INTO RESPOSTACORRECTA "
                + " (idProva,tipusRonda,numPregunta,opcioCorrecta,"
                + "dataMod,usuariMod,dataAlta,usuariAlta) "
                + "VALUES(?,?,?,?,?,?,?,?)";      
        Integer n=0;
        setDeleteRespostesRonda(idProva,tipus);

           PreparedStatement ps = gestor.crearPreparedStatement(sql);
           for(PreguntaResposta pr:ronda.getRespostesRonda()){

                ps.setInt(1,idProva);                               
                ps.setString(2,tipus);
                ps.setInt(3, pr.getPregunta());
                ps.setString(4, pr.getResposta());               
                ps.setDate(5, new java.sql.Date(System.currentTimeMillis())); 
                ps.setInt(6, ronda.getUsuariModificacio().getIdIntern());
                ps.setDate(7,new java.sql.Date(System.currentTimeMillis()));
                ps.setInt(8,ronda.getUsuariModificacio().getIdIntern());
                if(ps.executeUpdate()>0){
                    n++;
                }                
           }            
           ps.close();           

        return n;
    }
    /**
     * Guardar les respostes correctes d'una ronda
     * @param idProva               identificador de la prova
     * @param tipusRonda            Tipus de ronda
     * @param pr                    Preguntes i respostes
     * @param dataAlta              Data d'alta
     * @param usuari                usuari d'alta
     * @throws SQLException
     * @throws EOlympicsException 
     */
    private void altaRespostaCorrecta(Integer idProva,String tipusRonda,PreguntaResposta pr,java.sql.Date dataAlta,Integer usuari) throws SQLException, EOlympicsException{
        String sql="INSERT INTO RESPOSTACORRECTA "
                + " (idProva,tipusRonda,numPregunta,opcioCorrecta,"
                + "dataAlta,usuariAlta) "
                + "VALUES(?,?,?,?,?,?)";        
       
           PreparedStatement ps = gestor.crearPreparedStatement(sql);
           
                ps.setInt(1, idProva);               
                ps.setString(2,tipusRonda);                
                ps.setInt(3,pr.getPregunta());
                ps.setString(4, pr.getResposta());
                ps.setDate(5, new java.sql.Date(System.currentTimeMillis())); 
                ps.setInt(6, usuari);
                ps.execute();
                     
           ps.close();   
    }
    /**
     * Cancela les respostes correctes d'una ronda
     * @param idProva               Identificador de la prova
     * @param tipus                 Tipus de ronda
     * @param ronda                 Ronda
     * @return
     * @throws EOlympicsExceptionProva
     * @throws EOlympicsException
     * @throws SQLException 
     */
    public int setCancelacioRespostesRonda(Integer idProva, String tipus,Ronda ronda) throws EOlympicsExceptionProva, EOlympicsException, SQLException{
        String sql="UPDATE RESPOSTACORRECTA "
                + " SET dataBaixa=?,usuariBaixa=? "
                + "WHERE idProva=? "
                + "AND tipusRonda=? "
                + "AND numPregunta=? ";
                
        Integer n=0;
       
           PreparedStatement ps = gestor.crearPreparedStatement(sql);
           for(PreguntaResposta pr:ronda.getRespostesRonda()){
                ps.setDate(1, new java.sql.Date(System.currentTimeMillis())); 
                ps.setInt(2, ronda.getUsuariBaixa().getIdIntern());
                ps.setInt(3,idProva);                              
                ps.setString(4,tipus);
                ps.setInt(5, pr.getPregunta());                
                if(ps.execute()) n++;
           }            
           ps.close();           
       
        return n;
    }
    /**
     * Guarda les modificacions d'una ronda
     * @param idProva                   identificador de la prova
     * @param tipus                     Tipus de ronda
     * @param ronda                     Ronda
     * @throws EOlympicsException
     * @throws EOlympicsExceptionProva
     * @throws SQLException 
     */
    private void setModificacioRonda(Integer idProva, String tipus,Ronda ronda ) throws EOlympicsException, EOlympicsExceptionProva, SQLException{
        Statement st=gestor.creaSentencia();
        String sql="UPDATE RONDA "
                + "SET nombrePreguntes=?,dataIniciRealitzacio=?,dataFiRealitzacio=?,dataMod=?,usuariMod=? "
                + "WHERE idProva=? "
                + "AND tipusRonda=? ";
       PreparedStatement ps = gestor.crearPreparedStatement(sql);
       
           ps.setInt(1, ronda.getNombrePreguntes());           
           ps.setDate(2, new java.sql.Date(ronda.getDataIniRealitzacio().getTime()));
           ps.setDate(3, new java.sql.Date(ronda.getDataFiRealitzacio().getTime()));           
           ps.setDate(4, new java.sql.Date(System.currentTimeMillis()));         
           ps.setInt(5, ronda.getUsuariModificacio().getIdIntern());         
           ps.setInt(6, idProva);
           ps.setString(7, tipus);           
           ps.executeUpdate();
           ps.close();
           setModificacioRespostesRonda(idProva,tipus,ronda);

    }
    /**
     * Esborra les respostes correctes d'una ronda
     * @param idProva               identificador de la prova
     * @param tipus                 tipus de ronda
     * @throws SQLException 
     */
    private void setDeleteRespostesRonda(Integer idProva, String tipus) throws SQLException{
        Statement st=gestor.creaSentencia();
        String sql ="DELETE FROM RESPOSTACORRECTA "
                + "WHERE idProva="+idProva  
                + " AND tipusRonda='"+tipus+"'";
                st.executeUpdate(sql);
                st.close();
    }           
    /**
     * Cancela una ronda    
     * @param idProva           identificador de la prova
     * @param tipus             Tipus de ronda
     * @param ronda             Ronda
     * @throws SQLException
     * @throws EOlympicsException 
     */
    public void setCancelacioRonda(Integer idProva, String tipus, Ronda ronda ) throws SQLException, EOlympicsException{
        Statement st=gestor.creaSentencia();
        String sql="UPDATE RONDA "
                + "SET dataBaixa=?,usuariBaixa=? "
                + "WHERE idProva=? "
                + "AND tipusRonda=? ";
       PreparedStatement ps = gestor.crearPreparedStatement(sql);
          
           ps.setDate(1, new java.sql.Date(System.currentTimeMillis()));           
           ps.setInt(2, ronda.getUsuariBaixa().getIdIntern());         
           ps.setInt(3, idProva);
           ps.setString(4, tipus);           
           ps.executeUpdate();
           ps.close();
           setCancelacioRespostesRonda(idProva,tipus,ronda);
             
    }
    /**
     * Guarda una ronda
     * @param idProva           Identificador de la prova
     * @param tipus             Tipus de ronda
     * @param ronda             Ronda
     * @throws EOlympicsException
     * @throws SQLException 
     */
    public void guardarRonda(Integer idProva, String tipus,Ronda ronda) throws EOlympicsException, SQLException{     
        if(existeixRonda(idProva,tipus)){
            setModificacioRonda(idProva,tipus,ronda);
        }else{
            setAltaRonda(idProva,tipus,ronda);
        }
    }
    /**
     * Comprova si existeix una Ronda
     * @param idProva           Identificador de la prova
     * @param tipus             Tipus de prova
     * @return  Cert si existeix, fals en cas contrari
     * @throws EOlympicsException
     * @throws SQLException 
     */
    private boolean existeixRonda (Integer idProva,String tipus) throws EOlympicsException, SQLException{
        boolean existeix=false;
        Statement st=gestor.creaSentencia();
        String sql="SELECT R.idProva "
                + "FROM RONDA R "                
                + "WHERE R.idProva="+ idProva 
                + " And R.tipusRonda='"+tipus+"'";
        
            ResultSet rs=st.executeQuery(sql);
            if (rs.next()){                              
                existeix=true;
            }
            st.close();
            rs.close();        
        return existeix;
    }
    
}
